namespace ghost {
	enum LoadedState{
		/**未加载*/UNLOAD,
		/**加载中*/LOADING,
		/**加载完成*/LOADED,
		/**加载失败*/LOADFAIL
	}
	export interface ISeqResDict{
		[key:string]:ISeqResInfo;
	}
	export interface ISeqResInfo{
		/**资源是否已加载*/
		loaded:boolean;		
		/**资源类型0 图片 1图集*/type:number;
		/**大图序列的索引编号*/index:number;
		/**资源对应的动作状态*/sts?:number;
		/**资源引用*/resObj:ResObject;
	}
	/**序列播放器，AniRole使用*/
	export class SeqSprite extends GYSprite implements IResource{
		public owner:Role;
		private _offsetX:number[];
		private _offsetY:number[];
		private _offsetH:number[];
		private _scaleXRate:number[];
		private _scaleYRate:number[];
		private _alphas:number[];
		private _rate:number[];
		private _rateLen:number;
		private _xLen:number;
		private _yLen:number;
		private _sclXLen:number;
		private _sclYLen:number;
		private _alphaLen:number;
		private _clothesRate:any;		
		public loops:number;
		private _loopsCount:number;
		private _startRate:number;
		private _hitRanges:number[][];
		private _atkRanges:number[][];
		public atkRange:number[];
		public hitRange:number[];
		public curRate:number;
		public curPercent:number;
		public playEnd:boolean;
		public shape:Laya.Sprite;
		public globalScl:number;
		public timeTicker:map2D.TimeTicker;		
		public _indexLen:number;
		public duration:number;
		public actionDuration:number;	
		protected _playRate:number;	
		/**是否帧循环播放，默认false，停止在最后一帧*/
		public _rateLoop:boolean;
		protected _scene:map2D.SceneManagerBase;
		protected _loaddingDict:{[key:string]:boolean};
		protected _resDict:ISeqResDict;
		protected _images:string[];
		/**0 未加载 1 加载中 2 加载结束 3加载失败，此属性用于判断是否具有handle，可能资源已经加载但是在等待回收中，handle会为0*/
		protected _loaded:number;	
		protected _loadCount:number;
		protected _seqTextures:Laya.Texture[];
		/**2d本地坐标X*/protected _translateX:number;
		/**2d本地坐标Y*/protected _translateY:number;
		protected _matrix:Laya.Matrix;		
		protected _sts:number;
		public constructor(scene:map2D.SceneManagerBase) {
			super();
			let s = this;
			s.globalScl = 1;
			s._playRate = 1;
			s._scene = scene;
			s._images = [];
			s._seqTextures = [];
			s._resDict = {};
			s.timeTicker = new map2D.TimeTicker(scene);
			s._matrix = new Laya.Matrix;
		}
		public set playRate(val:number)
		{
			let s= this;
			if(s._playRate == val)
				return;
			s._playRate = val;
			let percent:number = s.timeTicker.getPercent();
			if(percent == 0)return;
			s.timeTicker.duration = s.duration * s.playRate;
			s.timeTicker.setPercent(percent);
		}
		public get playRate():number
		{
			return this._playRate;
		}
		public setConfig(clothes:any,direction:number,sts:number):void
		{
			let s= this;
			let clothesRate:any;						
			let stsChange:boolean;
			clothesRate = clothes.rate[direction]?clothes.rate[direction]:clothes.rate[0];	
			s.alpha = 1;
			s._playRate = 1;
			s.curRate = 0;
			stsChange = s._sts != sts;
			s._sts = sts;	
			
			s._rate = clothesRate.index;
			s._indexLen = s._rate?s._rate.length:0;
			s._rateLen = clothesRate.rateLength?clothesRate.rateLength:clothesRate.index.length;
					
			let duration:number = s.actionDuration > 0?s.actionDuration:(clothesRate.duration?clothesRate.duration:s._indexLen*CommonUtil.delta)|0;
			s.duration = duration > 0?duration:(s._indexLen*CommonUtil.delta);			
			if(s._clothesRate == clothesRate)	
			{
				if(StsType.attackAction(s._sts))
				{
					s.timeTicker.init(NaN, duration);
					s.playEnd = false;		
					s._loopsCount = 0;
				}				
				return;
			}	
			if(stsChange)
				s.timeTicker.init(NaN, duration);
			s.playEnd = false;		
			s._loopsCount = 0;
			s._clothesRate = clothesRate;			

			s._offsetX = clothesRate.offsetX;
			s._xLen= s._offsetX.length;
			s._offsetY = clothesRate.offsetY;			
			s._yLen= s._offsetY.length;
			s._offsetH = clothesRate.offsetH;
			s._alphas = clothesRate.alphas;
			s._alphaLen	= s._alphas?s._alphas.length:0;
			s._rate = clothesRate.index;
			s._rateLen = duration/CommonUtil.delta|0;

			s._scaleXRate = clothesRate.scaleX;
			s._sclXLen= s._scaleXRate?s._scaleXRate.length:0;
			s._scaleYRate = clothesRate.scaleY;			
			s._sclYLen= s._scaleYRate?s._scaleYRate.length:0;
			
			s._rateLoop = clothesRate.rateLoop == null || clothesRate.rateLoop == 1;
			s.loops = clothes.loops?clothes.loops:NaN;			
			s._hitRanges = clothesRate.hitRange;
			s._atkRanges = clothesRate.atkRange;
			
			s._startRate = -1;
			s.curRate = 0;
			s._loadCount = 0;
			s.setImages(s._clothesRate.images);
			s._loaded = s._loadCount == 0?LoadedState.LOADED:LoadedState.LOADING;			
			if(s._loaded == LoadedState.LOADED)
			{
				s.initSeqTexture();				
			}			
			s.loop(s._scene.timeTick);
		}
		/**单张序列图加载（非图集）*/
		public setImages(val:string[]):void
		{
			let s =this;
			let url:string;			
			s.ref();
			s._images = [];
			if(val && val.length)
			{
				let i:number,len:number;
				len = val.length;
				for(i=0;i<len;++i)
				{
					if(val[i] == "-1")
						continue;
					s._images[i] = url = Conf.image + s._clothesRate.atlas + val[i] + ".png";
					s.loadSeqRes(url, url);
				}
			}	
		}	
		/**加载序列资源
		 * @param resKey 序列唯一key
		 * @param loadUrl 加载路径
		*/
		private loadSeqRes(resKey:string,loadUrl:string):void
		{
			let s = this;
			let resObj:ResObject;
			let isImage:boolean;
			if(s._resDict[resKey] == null)
				s._resDict[resKey] = {loaded:false, type:1, index:0, resObj:null};								
			
			resObj = Main.instance.getRes(loadUrl, false, true);
			if(resObj)
			{						
				resObj.getRes();
				s._resDict[resKey].resObj = resObj;
				s._resDict[resKey].loaded = true;
			}						
			else
			{
				++s._loadCount;
				s._loaddingDict[resKey] = true;
				Main.instance.myLoader.loadPath(loadUrl, s.resLoadComp, s);
			}
			
		}	
		/**初始化序列纹理数组(需要动作配置装入)*/
		protected initSeqTexture():void
		{
			let s = this;
			let i:number,len:number;
			s._seqTextures = [];
			if(s._images && s._images.length > 0)
			{				
				len = s._images.length;
				for(i=0;i<len;++i)
				{					
					s._seqTextures[i] = Main.instance.getRes(s._images[i]);
				}					
			}			
			// s.resetAreaSize(s._seqTextures[0]);			
		}
		protected resLoadComp(loadInfo:LoadInfo):void{
			let s = this;			
			let resInfo:ISeqResInfo, res:any;
			let url:string;
			if(s._destroyed)return;	
			
			url = loadInfo.path;
			resInfo = s._resDict[url];						
			if(s._loaddingDict[url])
			{
				delete s._loaddingDict[url];
				--s._loadCount;
			}
			else
				return;			
			if(loadInfo.content && loadInfo.content.res)
			{		
				loadInfo.content.getRes();
				resInfo.resObj = loadInfo.content;
				resInfo.loaded = true;
				if(s._loadCount == 0)
				{
					if(s._loaded != LoadedState.LOADFAIL)									
					{
						s._loaded = LoadedState.LOADED;												
						s.initSeqTexture();
					}
					s.loop(s._scene.timeTick);
				}				
				return;
			}	
			s._loaded = LoadedState.LOADFAIL;
		}
		public loop(timeTick:number):void
		{
			let s= this;
			if(s.timeTicker._paused)
				return;		
			if(s._clothesRate && !s.playEnd)
			{				
				let ticker:map2D.TimeTicker;
				let m:Laya.Matrix;	
				let sclX:number,sclY:number,tx:number,ty:number,percent:number;
				ticker = s.timeTicker;
				if(ticker.startTime != ticker.startTime)
					ticker.startTime = timeTick;				
				ticker.playRateUpdate();				
				ticker.duration = s.duration * s.playRate;
				percent = ticker.getPercent();

				let temp:number,rateInd:number;				
				
				s.curPercent = percent;
				s.curRate = percent * s._rateLen | 0;

				m = s._matrix;
				m.identity();
				if(s._xLen > 0)
				{
					temp = s.getIndex(percent, s._offsetX, s._xLen);
					tx = -temp;
				}
				else
					tx = 0;
				if(s._yLen > 0)
				{
					temp = s.getIndex(percent, s._offsetY, s._yLen);
					ty = -temp;
				}			
				else
					ty = 0;	

				if(s._sclXLen > 0)
				{
					temp = s.getIndex(percent, s._scaleXRate, s._sclXLen);
					sclX = temp * s.globalScl;
				}
				else									
					sclX = s.globalScl;
				if(s._sclYLen > 0)
				{
					temp = s.getIndex(percent, s._scaleYRate, s._sclYLen);						
					sclY = temp * s.globalScl;					
				}
				else				
					sclY = s.globalScl;							
				
				m.translate(tx,ty);				
				m.scale(sclX*s.owner._dirScaleX,sclY*s.owner._dirScaleY);
				
				// if(s._rotateLen > 0)
				// {
				// 	temp = s.getIndex(percent, s._rotate, s._rotateLen);						
				// 	m.rotate(temp * GYLite.MathConst.ROTATION_ANGLE);
				// }				
				
				if(s._alphaLen > 0)				
					s.alpha = s.getIndex(percent, s._alphas, s._alphaLen);
				s._translateX = m.tx;//Laya的matrix会把tx赋值给显示对象的x并清空tx，所以保留一下变量值到translateX
				s._translateY = m.ty;	
				s.scaleX *= s.owner._dirScaleX;
				s.scaleY *= s.owner._dirScaleY;
				if(s._hitRanges && s._hitRanges.length > 0)									
					s.hitRange = s._hitRanges.length == 1?s._hitRanges[0]:s.getIndex(percent, s._hitRanges, s._hitRanges.length, s._rateLoop);									
				else
					s.hitRange = null;				
				if(s._atkRanges && s._atkRanges.length > 0)
				{
					if(s._atkRanges[-1])
						s.atkRange = s._atkRanges[-1];
					else
					{
						rateInd = percent * s._indexLen;
						s.atkRange = s._atkRanges[rateInd];
					}					
				}
				else
					s.atkRange = null;

				//显示debug外框		
				if(s.hitRange && GameManager.debug)
				{					
					let sclX:number,sclY:number;
					sclX = s.scaleX;
					sclY = s.scaleY;
					let arr:number[];					
								
					let i:number,len:number;
					let shape:Laya.Sprite					
					shape = s.shape = s.shape || new GYSprite;			
					s.parent.addChild(shape);
					
					let g:Laya.Graphics = shape.graphics;				
					g.clear();
					arr = s.hitRange;
					len = arr.length;
					if(len > 4)
					{
						for(i=2;i<len;i+=2)							
							g.drawLine((arr[i-2]*sclX),(arr[i-1]*sclY),(arr[i]*sclX),(arr[i+1]*sclY),"#00ff00",1);
						g.drawLine((arr[i-2]*sclX),(arr[i-1]*sclY),(arr[0]*sclX),(arr[1]*sclY),"#00ff00",1);					
					}					
				}
				if(s._loaded == LoadedState.LOADED && s._seqTextures)
				{
					rateInd = s.getIndex(percent, s._rate, s._indexLen, s._rateLoop);				
					if(rateInd >= 0)
					{
						if(s._seqTextures[rateInd] == null)
						{
							console.warn("衣服空帧:"+rateInd);
							return;
						}
						s.texture = s._seqTextures[rateInd];
					}
				}
				
				if(s.loops == s.loops && (ticker.getCurTime()) >= ticker.duration)
				{					
					s._startRate = -1;
					++s._loopsCount;
					if(s._loopsCount == s.loops)
						s.playEnd = true;
				}
				s.transform = m;
			}
		}
		protected getIndex(percent:number, arr:any[], indexLen:number, rateLoop:boolean=false):any
		{
			let s= this;
			let lastIndex:number,rateInd:number;
			lastIndex = indexLen - 1;
			rateInd = Math.floor(percent * lastIndex);
			if(rateInd < indexLen)
				return arr[rateInd];			
			return rateLoop?arr[rateInd%indexLen]:(lastIndex > -1?arr[lastIndex]:0);
		}
		public onPause():void
		{
			let s =this;			
			s.timeTicker.pause();
		}
		public onResume():void
		{
			let s = this;			
			s.timeTicker.resume();
		}
		public getX():number
		{			
			return this._translateX;
		}
		public getY():number
		{			
			return this._translateY;
		}
		public getScaleX():number
		{
			return this._matrix.a*this.owner._dirScaleX;
		}
		public getScaleY():number
		{
			return this._matrix.d*this.owner._dirScaleY;
		}
		protected ref():void
		{
			let s = this;
			s._loaddingDict = {};
			for(var key in s._resDict)	
			{
				if(s._resDict[key].resObj)
				{
					s._resDict[key].resObj.relRes();
					//引用为0,1秒后再判断仍然是0则销毁，否则继续使用
					if(s._resDict[key].resObj.count == 0)
						Laya.timer.once(1000, s, s.deleteRes, [s._resDict[key].resObj, s._resDict[key].resObj.pathKey]);
						
				}	
				delete s._resDict[key];
			}
		}		
		protected deleteRes(resObj:ResObject, pathKey:string):void
		{
			let s = this;
			if(resObj.pathKey == pathKey)
			{
				if(resObj.count == 0)
					GYLoader.deleteResByKey(pathKey);
			}			
		}

		public dispose():void
		{
			let s= this;
			s.destroy(true);
			s.ref();
			s._loaded = 0;			
			s._seqTextures = null;
			if(s.shape)
				s.shape.destroy(true);
		}		
	}
}